#include "stdafx.h"
#include "AsioSession.h"

bool Session::Connect()
{
	if (!DoCreateSocketAndConnect(mConnStr))
		return false;
	AsyncReadSome();
	return true;
}

Session::~Session()
{
	if (IsConnected())
		Close();
}

void Session::handle_read(const boost::system::error_code& error, size_t bytes_transferred)
{
	std::string s(mRecvBuf, bytes_transferred);
	{
		std::unique_lock<std::mutex> _(mLock);
		mMessageQueue.push_back(s);
		Record(s, true, true);
	}
	AsyncReadSome();
}

std::string Session::GetMessage()
{
	std::unique_lock<std::mutex> _(mLock);
	if (mMessageQueue.empty())
		return "";
	std::string message = mMessageQueue.front();
	mMessageQueue.pop_front();
	return message;
}

bool Session::SendSome(const std::string& message)
{
	bool ret = DoSendSome(message);
	Record(message, false, ret);
	return ret;
}

void Session::Record(const std::string& message, bool isrecv, bool success)
{
	if (mEnableRecord && !mRecordDir.empty())
	{

	}
}

std::atomic_bool Session::mEnableRecord;

std::string Session::mRecordDir;

bool UDPSession::DoSendSome(const std::string& message)
{
	if (mSocket == nullptr)
		return false;
	return mSocket->send_to(boost::asio::buffer(message.data(), message.length()), sender_endpoint_) == message.length();
}

bool UDPSession::DoCreateSocketAndConnect(const std::string& connstr)
{
	std::string address;
	int port = -1;

	size_t pos = connstr.find(':');
	if (pos == std::string::npos)
		port = atoi(connstr.c_str());
	else
	{
		address = connstr.substr(0, pos);
		port = atoi(connstr.substr(pos + 1).c_str());
	}

	if (port <= 0)
		return false;

	if (address.empty())
		mSocket = new udp::socket(mIOService, udp::endpoint(udp::v4(), port));
	else
		mSocket = new udp::socket(mIOService, udp::endpoint(address::from_string(address), port));

	return true;
}

void UDPSession::AsyncReadSome()
{
	mSocket->async_receive_from(boost::asio::buffer(mRecvBuf, max_length), sender_endpoint_, boost::bind(&SocketSession < udp::socket>::handle_read, shared_from_this(),
		boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}

bool TCPSession::DoCreateSocketAndConnect(const std::string& connstr)
{
	std::string address;
	int port = -1;

	size_t pos = connstr.find(':');
	if (pos == std::string::npos)
		return false;

	address = connstr.substr(0, pos);
	port = atoi(connstr.substr(pos + 1).c_str());

	if (port <= 0)
		return false;

	mSocket = new tcp::socket(mIOService);
	server_endpoint = tcp::endpoint(address::from_string(address), port);

	boost::system::error_code ec;
	mSocket->connect(server_endpoint, ec);
	return ec;
}

bool SerialSession::DoCreateSocketAndConnect(const std::string& connstr)
{
	std::string port;
	
	size_t pos1 = connstr.find(',');
	if (pos1== std::string::npos)
		return false;
	port = connstr.substr(0, pos1);

	mSocket = new boost::asio::serial_port(mIOService, port);
	size_t pos2 = connstr.find(',', pos1 + 1);
	int baud = 9600;
	if (pos1!= std::string::npos)
		baud = atoi(connstr.substr(pos1 + 1, pos2).c_str());
	mSocket->set_option(boost::asio::serial_port::baud_rate(baud));
	pos1 = pos2;
	pos2 = connstr.find(',', pos1 + 1);
	int databits = 8;
	if (pos1 != std::string::npos)
		databits = atoi(connstr.substr(pos1 + 1, pos2).c_str());
	mSocket->set_option(boost::asio::serial_port::character_size(databits));
	pos1 = pos2;
	pos2 = connstr.find(',', pos1 + 1);
	std::string parity = "N";
	if (pos1 != std::string::npos)
		parity = connstr.substr(pos1 + 1, pos2);
	if (parity == "O")
		mSocket->set_option(boost::asio::serial_port::parity(boost::asio::serial_port::parity::odd));
	else if (parity == "E")
		mSocket->set_option(boost::asio::serial_port::parity(boost::asio::serial_port::parity::even));
	else
		mSocket->set_option(boost::asio::serial_port::parity(boost::asio::serial_port::parity::none));
	pos1 = pos2;
	pos2 = connstr.find(',', pos1 + 1);
	std::string stopbits = "1";
	if (pos1 != std::string::npos)
		stopbits = connstr.substr(pos1 + 1, pos2);

	if (stopbits == "1")
		mSocket->set_option(boost::asio::serial_port::stop_bits(boost::asio::serial_port::stop_bits::one));
	else if (stopbits == "2")
		mSocket->set_option(boost::asio::serial_port::stop_bits(boost::asio::serial_port::stop_bits::two));
	else
		mSocket->set_option(boost::asio::serial_port::stop_bits(boost::asio::serial_port::stop_bits::onepointfive));

	mSocket->set_option(boost::asio::serial_port::flow_control());
	return true;
}
